package FastFDs;

import java.util.ArrayList;
import java.util.Scanner;

public class FastFDs {
	static ArrayList<String []> R=new ArrayList<String []>();
	static ArrayList<Integer []> Dr=new ArrayList<Integer []>();
	static ArrayList<Integer []> DrA=new ArrayList<Integer []>();
	static ArrayList<Integer []> Agreeset=new ArrayList<Integer []>();
	static ArrayList<Integer []> DrARemain=new ArrayList<Integer []>();
	static ArrayList<Integer []> CurrentOrder=new ArrayList<Integer []>();
	static ArrayList<Integer []> Result=new ArrayList<Integer []>();
	static ArrayList<Integer> Tmp=new ArrayList<Integer>();
	static ArrayList<Integer> Tmp1=new ArrayList<Integer>();
	static ArrayList<Integer> Tmp2=new ArrayList<Integer>();

	static String [] A={"1", "0",	"0",	"0",	"0",	"0"};
	static String [] B={"1", "0",	"0",	"1",	"1",	"0"};
	static String [] C={"1", "0",	"1",	"0",	"1",	"0"};
	static String [] D={"1", "1",	"0",	"1",	"0",	"0"};
	static String [] E={"1", "1",	"1",	"1",	"0",	"1"};
	static String [] F={"1", "1",	"1",	"0",	"1",	"1"};

	public static void main(String[] args) {
		R.add(A);
		R.add(B);
		R.add(C);
		R.add(D);
		R.add(E);
		R.add(F);
		do {
			System.out.println("1: Computing DrA ");
			System.out.println("2: Inprimer la list de Dr ");
			System.out.println("3: Inprimer la list de DrA ");
			System.out.println("4: Calculer Minimal ");
			Scanner input=new Scanner(System.in);
			int cs=input.nextInt();
			switch(cs)
			{
				case 1: 
					ComputingDrA(); break;
				case 2: 
					in(); break;
				case 3: 
					inDrA(); break;
				case 4: 
					FindMinimal(); break;
			}
			
			
			}while(true);
		}
	

	public static void ComputingDrA()
	{
			for(int i=0;i<R.size();i++)
			{
			String [] s=R.get(i);
			AgreeSet(s,0);
			AgreeSet(s,1);
			AgreeSet(s,2);
			AgreeSet(s,3);
			AgreeSet(s,4);
			AgreeSet(s,5);
			Tmp1.clear();
			Stripped_Partition();
			Agreeset.clear();
			}
			System.out.println("Le nombre Dr = "+Dr.size());
			Scanner input=new Scanner(System.in);
			System.out.println("Choisir l'attribute");
			int a=input.nextInt();
			DrA(a);
			System.out.println("Le nombre DrA = "+DrA.size());
	}
	
	
	/////////////////////////////////////////
	public static void FindMinimal()
	{
			init();
			for(int j=0;j<=((CurrentOrder.get(0)).length);)
			{
				
				//In the case CurrentOrder != NULL and DrARemain !=NULL
				if((CurrentOrder.get(j)).length!=0&(DrARemain.get(j).length)!=0)
				{
					Integer[] Current=CurrentOrder.get(j);
					ModifierCurrent(j);
					computeDrARemain(Current[0],j);
					CurrentOrdering(j+1);
					if(CurrentOrder.size()>1)
					Check(j);
					j++;

				}
				
				
				if((CurrentOrder.get(j)).length==0&(DrARemain.get(j).length)==0)
				{
					Integer [] result=new Integer[Tmp2.size()-1];
					for(int i=1;i<Tmp2.size();i++)
						result[i-1]=Tmp2.get(i);
					Tmp2.remove(j);
					Result.add(result);
					CurrentOrder.remove(j);
					DrARemain.remove(j);
					j--;
				} else
					if((CurrentOrder.get(j)).length==0|(DrARemain.get(j).length)==0)
						{
						Tmp2.remove(j);
						CurrentOrder.remove(j);
						DrARemain.remove(j);
						j--;
					  }
					
					if((CurrentOrder.get(j)).length==0)
						{	
						Tmp2.remove(j);
						CurrentOrder.remove(j);
						DrARemain.remove(j);
						j=j-1;
						}
					
					
					if(j<0&CurrentOrder.size()==0)
					{
						break;
					}
				}	
			inminimal();
			
	}
	
	//in danh sach Minimal cover
	public static void inminimal()
	{
		for(int i=0;i<Result.size();i++)
		{
			Integer [] minimal=Result.get(i);
			for(int j=0;j<minimal.length;j++)
				System.out.print(minimal[j]);
			System.out.println("");
		}
		
		
	}
	//Init Current Ordering
	public static void init()
	{
		Integer [] DrARemaininit={0,1,2,3};
		Tmp2.add(0);
		DrARemain.add(DrARemaininit);
		CurrentOrdering(0);
	}
	
	public static void ModifierCurrent(int position) // the position of CurrentOrder which need to modify
	{
		Integer [] Crr=CurrentOrder.get(position);
		Integer [] temp=new Integer [Crr.length-1];
		for(int i=0;i<Crr.length-1;i++)
		{
			temp[i]=Crr[i+1];
		}
		Tmp2.add(Crr[0]);
		CurrentOrder.remove(position);
		CurrentOrder.add(temp);
	}
	

	
	//Etap 2 Compute DrA sans Attribute qui a defini
	public static void computeDrARemain(int Attribute,int position)  //Attribute : Thuoc tinh can so sanh voi DrARemain hien tai
	{															// Position : Vi tri cua DrARemain hien tai
		Integer [] DrARemainning=DrARemain.get(position);
		for(int i=0;i<DrARemainning.length;i++)
		{
			int pos=DrARemainning[i];
			Integer [] dra=DrA.get(pos);
			if(dra[0]!=Attribute&dra[1]!=Attribute)
			Tmp.add(pos);
		}
		Integer [] temp=new Integer[Tmp.size()];
		Tmp.toArray(temp);
		Tmp.clear();
		DrARemain.add(temp);
	}
	
	
	// Compute Current Ordering
	public static void CurrentOrdering(int position)  // Position : Vi tri cua DrARemain can tinh CurrentOrdering
	{	
		Integer [] pos=DrARemain.get(position);
		for(int i=0;i<pos.length;i++)
		{	Integer [] dra = DrA.get(pos[i]);
			for(int j=0;j<dra.length;j++)
				{
				Integer valeur=dra[j];
				if(!Tmp.contains(valeur))
					Tmp.add(valeur);
				}
		}
		Integer [] temp=new Integer[Tmp.size()];
		Tmp.toArray(temp);
		Tmp.clear();
		Integer [] Current=Arranger(temp);
		CurrentOrder.add(Current);
	}
	
	
	//Check
	public static void Check(int position)
	{
		Integer[] Crr1=CurrentOrder.get(position);
		Integer[] Crr2=CurrentOrder.get(position+1);
		for(int i=0;i<Crr1.length;i++)
			Tmp.add(Crr1[i]); 
		
		
		for(int j=0;j<Crr2.length;j++)
			if(Tmp.contains(Crr2[j]))
				Tmp1.add(Crr2[j]);
		
		Integer[] tmp=new Integer[Tmp1.size()];
		         Tmp1.toArray(tmp);
		         CurrentOrder.remove(position+1);
		         CurrentOrder.add(tmp);
		         Tmp.clear();
		         Tmp1.clear();
		   
	}
	
	//Arranger Current Order
	public static Integer[] Arranger(Integer [] input)
	{
		int min=0;
		  for(int i=0;i<input.length;i++)
			  for(int j=i+1;j<input.length;j++)
			  {
				  if(input[i]>input[j])
				  {
					  min=input[i];
					  input[i]=input[j];
					  input[j]=min;  
				  }
			  }
		  return input;
	}
	
	//println Dr
	public static void in()
	{
		int i,j;
		int size=Dr.size();
		for(i=0;i<size;i++)
		{
			Integer [] dr=Dr.get(i);
			for(j=0;j<dr.length;j++)
				System.out.print(dr[j]);
			
			System.out.println(" ");
		}

	}
	// println DrA
	public static void inDrA()
	{
		int i,j;
		int size=DrA.size();
		for(i=0;i<size;i++)
		{
			Integer [] dra=DrA.get(i);
			for(j=0;j<dra.length;j++)
				System.out.print(dra[j]);
			System.out.println(" ");
		}

	}
	
	//Computing AgreeSet
	public static void AgreeSet(String A[],int t)
	{
		int i=0;
		int j;
		Integer tmp=new Integer(t);
		if(!Tmp1.contains(tmp))
		{
		Tmp.add(tmp);
		Tmp1.add(tmp);
		for(i=t+1;i<6;i++)
			//6= nombre de t de l'atribute A
			{
			Integer tmp1=new Integer(i);
			if(!Tmp1.contains(tmp1))
				{if(A[t]==A[i])
				{
					Tmp.add(tmp1);
					Tmp1.add(tmp1);
				}
				}
		}
		if(Tmp.size()>1)
		{
		Integer agreeset[] = new Integer[Tmp.size()];
		for(j=0;j<Tmp.size();j++)
		{
			
			int tmp2=Tmp.get(j);
			int valeur=0;
			valeur=tmp2;
			agreeset[j]=valeur;
		}
		Tmp.clear();
		Agreeset.add(agreeset);
	}
		else Tmp.clear();
		}

	}
	
	//Computing Stripped Partition
	public static void Stripped_Partition() 
	{
		int i,j;
		int k;
		int size=Agreeset.size();
		for(k=0;k<size;k++)
		{
		Integer [] r=Agreeset.get(k); 
		for(i=0;i<r.length;i++)
			for(j=i+1;j<r.length;j++)
			{CompareT(r[i],r[j]);}
		}
	}
	///////Compare entre t1 et t2
	public static void CompareT(int t1,int t2)
	{
		for(int i=0;i<R.size();i++)
			{
				String[] r=R.get(i);
				if(r[t1]==r[t2])
				{
					Integer tmp=new Integer(i);
					Tmp.add(tmp);					
				}
			}
		Integer stripped[] = new Integer[Tmp.size()];
		Tmp.toArray(stripped);
		Tmp.clear();
		Integer [] dr=ConverttoDr(stripped);
		if(Dr.size()==0)
			Dr.add(dr);
			else
				if(Dr.size()!=0)
				{
				int result=Intermediare(dr);
				if(result==Dr.size())
				Dr.add(dr);
				}

		

	}

	// Compute Dr Attribute
	public static void DrA(int Attribute)
	{
		Integer obj=new Integer(Attribute);
		for(int i=0;i<Dr.size();i++)
		{
			Integer [] dr=Dr.get(i);
			for(int j=0;j<dr.length;j++)
			{
				int in=dr[j];
				Tmp.add(in);
			}
			if(Tmp.contains(obj))
				{
				Tmp.remove(obj);
				Integer [] dra=new Integer[Tmp.size()];
				Tmp.toArray(dra);
				DrA.add(dra);
				Tmp.clear();
				}
			else Tmp.clear();
		}
	}
	
	
	public static Integer[] ConverttoDr(Integer [] Stripped)
	{
			Integer [] dr=new Integer[R.size()-Stripped.length];
		  int count=0;
		  for(int i=0;i<Stripped.length;i++)
		  {	
			  Integer in=Stripped[i];
			  Tmp.add(in);
		  }
		  for(int j=0;j<R.size();j++)
		  {
			  Integer inn=j;
			  if(!Tmp.contains(inn))
			  {
				  dr[count]=j;
				  count=count+1;
			  }
		  }
		  Tmp.clear();
		  return dr;
	}
	
	// Intermediare
	public static int Intermediare(Integer [] rinput)
	{
		  int count=0;
		  for(int i=0;i<Dr.size();i++)
		  {
			  Integer[] r=Dr.get(i);
			  if(Comparediff(r,rinput))
				  count=count+1;
		  }
		  return count;
		
	}
	// Difference dr1[] and  dr2[]
	  public static boolean Comparediff(Integer [] r1,Integer [] r2)
	  {
		  if(r1.length!=r2.length)
			  return true;
		  if(r1.length==r2.length)
		  {
			  for(int i=0;i<r1.length;i++)
			  {
				  if(r1[i]!=r2[i])
					  return true;
			  }
		  }
		return false;
	}
}
	

